{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Practical Deep Learning for Coders, v3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Lesson7_resnet_mnist"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MNIST CNN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%reload_ext autoreload\n",
    "%autoreload 2\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from fastai.vision import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Data 数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "path = untar_data(URLs.MNIST)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[PosixPath('/home/ubuntu/.fastai/data/mnist_png/training'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/testing')]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "path.ls()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "il = ImageList.from_folder(path, convert_mode='L')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/4/44688.png')"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "il.items[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "defaults.cmap='binary'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ImageList (70000 items)\n",
       "[Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28)]...\n",
       "Path: /home/ubuntu/.fastai/data/mnist_png"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "il"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMUAAADDCAYAAAAyYdXtAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAABLZJREFUeJzt3b9LlW0cx3HNh4aEaAijQoSg1lZFGoLqL2hwaGvrH3CXpgKJFBrEwcXB/oeGoGiLIJwaEpGw3JxKy2d8eD7ne8M5cX55fL3GL4fba+jthVfnvu/xk5OTMeA/5wa9ABg2ooAgCgiigCAKCKKAIAoI//T55/lPEYbJeDW0U0AQBQRRQBAFBFFAEAUEUUAQBQRRQBAFBFFAEAUEUUAQBQRRQBAFBFFAEAUEUUAQBQRRQOj30zw4pT58+FDO5+bmyvnbt2/L+Z07d7q2pl6xU0AQBQRRQBAFBFFAcPpEW16+fFnOx8fLx7GOrayslHOnT3AKiQKCKCCIAoIoIDh94n9+/PhRzt+9e9fRda5evdqN5QyEnQKCKCCIAoIoIIgCgtOnNn379q2cf/r0qZzfv3+/ZTYxMdHVNfXC9vZ2Od/d3e3oOo8ePerGcgbCTgFBFBBEAUEUEEQBwelTm169elXOnz59Ws4PDw9bZpOTk11dUy+8fv160EsYODsFBFFAEAUEUUAQBQSnT2F5ebmcP3v2rM8r6b2jo6OW2efPnzu6xvz8fDm/ffv2X61pGNgpIIgCgiggiAKCKCCc2dOnvb29cr66ulrOf/36Vc5Pw910Td68edMya3pXXZO7d++W8/Pnz//VmoaBnQKCKCCIAoIoIIz8H9rHx8flfG1trZx//fq1o+tvbW2V89NwQ1EnD02+fv16OX/8+HG3ljM07BQQRAFBFBBEAUEUEEb+9KnpNGlpaamj68zOzpbzBw8edLqkoXFwcND2Zy9fvlzOZ2ZmurWcoWGngCAKCKKAIAoIooAw8qdP3dL0eqvnz5+X83v37rV97Vu3bpXzqamptq/xN9bX19v+7PT0dA9XMlzsFBBEAUEUEEQBQRQQxk9OTvr58/r6w8bGxsa+fPlSzptOfAbh5s2b5bzXp0/v379vmTX9e9jc3CznCwsLXV1Tn41XQzsFBFFAEAUEUUAQBYSRP33a398v50130u3s7PRyOUPv2rVr5Xx7e7ucX7x4sZfL6TWnT9AOUUAQBQRRQBAFhJG/8+7KlSvl/OPHj+W86XlQL1686Nqahtnc3Fw5P+WnTB2xU0AQBQRRQBAFBFFAGPnvPnXqz58/5fz3798dXWd5eblldnR0VH626Ynely5dKudN39tqulPvxo0b5fz79+8ts9XV1fKzT548KeennO8+QTtEAUEUEEQBYeS/5tGpc+fq3xNN8yaLi4vdWE5HNjY2ynn1BzXN7BQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUENx5d4ZduHChZfbw4cMBrGS42CkgiAKCKCCIAoIoIDh9OsOqh0YfHByUn216ePMoslNAEAUEUUAQBQRRQPB6rxHy8+fPcj4zM1POvd7L672gLaKAIAoIooAgCghOnzjLnD5BO0QBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAGh36/3Kh8pAsPETgFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQB4V995LZxp9qfvwAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "il[0].show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sd = il.split_by_folder(train='training', valid='testing')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ItemLists;\n",
       "\n",
       "Train: ImageList (60000 items)\n",
       "[Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28)]...\n",
       "Path: /home/ubuntu/.fastai/data/mnist_png;\n",
       "\n",
       "Valid: ImageList (10000 items)\n",
       "[Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28)]...\n",
       "Path: /home/ubuntu/.fastai/data/mnist_png;\n",
       "\n",
       "Test: None"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/4'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/6'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/8'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/0'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/9'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/1'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/3'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/2'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/5'),\n",
       " PosixPath('/home/ubuntu/.fastai/data/mnist_png/training/7')]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(path/'training').ls()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ll = sd.label_from_folder()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "LabelLists;\n",
       "\n",
       "Train: LabelList\n",
       "y: CategoryList (60000 items)\n",
       "[Category 4, Category 4, Category 4, Category 4, Category 4]...\n",
       "Path: /home/ubuntu/.fastai/data/mnist_png\n",
       "x: ImageList (60000 items)\n",
       "[Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28)]...\n",
       "Path: /home/ubuntu/.fastai/data/mnist_png;\n",
       "\n",
       "Valid: LabelList\n",
       "y: CategoryList (10000 items)\n",
       "[Category 4, Category 4, Category 4, Category 4, Category 4]...\n",
       "Path: /home/ubuntu/.fastai/data/mnist_png\n",
       "x: ImageList (10000 items)\n",
       "[Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28), Image (1, 28, 28)]...\n",
       "Path: /home/ubuntu/.fastai/data/mnist_png;\n",
       "\n",
       "Test: None"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ll"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = ll.train[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4 torch.Size([1, 28, 28])\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMUAAADDCAYAAAAyYdXtAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAABLZJREFUeJzt3b9LlW0cx3HNh4aEaAijQoSg1lZFGoLqL2hwaGvrH3CXpgKJFBrEwcXB/oeGoGiLIJwaEpGw3JxKy2d8eD7ne8M5cX55fL3GL4fba+jthVfnvu/xk5OTMeA/5wa9ABg2ooAgCgiigCAKCKKAIAoI//T55/lPEYbJeDW0U0AQBQRRQBAFBFFAEAUEUUAQBQRRQBAFBFFAEAUEUUAQBQRRQBAFBFFAEAUEUUAQBQRRQOj30zw4pT58+FDO5+bmyvnbt2/L+Z07d7q2pl6xU0AQBQRRQBAFBFFAcPpEW16+fFnOx8fLx7GOrayslHOnT3AKiQKCKCCIAoIoIDh94n9+/PhRzt+9e9fRda5evdqN5QyEnQKCKCCIAoIoIIgCgtOnNn379q2cf/r0qZzfv3+/ZTYxMdHVNfXC9vZ2Od/d3e3oOo8ePerGcgbCTgFBFBBEAUEUEEQBwelTm169elXOnz59Ws4PDw9bZpOTk11dUy+8fv160EsYODsFBFFAEAUEUUAQBQSnT2F5ebmcP3v2rM8r6b2jo6OW2efPnzu6xvz8fDm/ffv2X61pGNgpIIgCgiggiAKCKCCc2dOnvb29cr66ulrOf/36Vc5Pw910Td68edMya3pXXZO7d++W8/Pnz//VmoaBnQKCKCCIAoIoIIz8H9rHx8flfG1trZx//fq1o+tvbW2V89NwQ1EnD02+fv16OX/8+HG3ljM07BQQRAFBFBBEAUEUEEb+9KnpNGlpaamj68zOzpbzBw8edLqkoXFwcND2Zy9fvlzOZ2ZmurWcoWGngCAKCKKAIAoIooAw8qdP3dL0eqvnz5+X83v37rV97Vu3bpXzqamptq/xN9bX19v+7PT0dA9XMlzsFBBEAUEUEEQBQRQQxk9OTvr58/r6w8bGxsa+fPlSzptOfAbh5s2b5bzXp0/v379vmTX9e9jc3CznCwsLXV1Tn41XQzsFBFFAEAUEUUAQBYSRP33a398v50130u3s7PRyOUPv2rVr5Xx7e7ucX7x4sZfL6TWnT9AOUUAQBQRRQBAFhJG/8+7KlSvl/OPHj+W86XlQL1686Nqahtnc3Fw5P+WnTB2xU0AQBQRRQBAFBFFAGPnvPnXqz58/5fz3798dXWd5eblldnR0VH626Ynely5dKudN39tqulPvxo0b5fz79+8ts9XV1fKzT548KeennO8+QTtEAUEUEEQBYeS/5tGpc+fq3xNN8yaLi4vdWE5HNjY2ynn1BzXN7BQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUENx5d4ZduHChZfbw4cMBrGS42CkgiAKCKCCIAoIoIDh9OsOqh0YfHByUn216ePMoslNAEAUEUUAQBQRRQPB6rxHy8+fPcj4zM1POvd7L672gLaKAIAoIooAgCghOnzjLnD5BO0QBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAGh36/3Kh8pAsPETgFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQBQRQQRAFBFBBEAUEUEEQB4V995LZxp9qfvwAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "x.show()\n",
    "print(y,x.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tfms = ([*rand_pad(padding=3, size=28, mode='zeros')], [])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ll = ll.transform(tfms)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bs = 128"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# not using imagenet_stats because not using pretrained model\n",
    "data = ll.databunch(bs=bs).normalize()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = data.train_ds[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMUAAADDCAYAAAAyYdXtAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAABKtJREFUeJzt3bFLVX0cx/Gsh4aCaIhEI4RAV9ckGoTsL3BoaGvrH2iXpgSJuuAgDi0N9T80BEVbBOHUUIRI5eakZjY+PJ/7vXFPnnu9Pb1e4xc59zf09oe/7jln7PDw8ATwr5PHvQAYNaKAIAoIooAgCgiigCAKCP8M+fP8pwijZKwa2ikgiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCCIAoIoIIgCgiggiAKCKCAM+01G/OXevHlTzufm5sr5y5cvu2bXr19vdU3JTgFBFBBEAUEUEEQBwekTQ/Xo0aNyPjZWvtL6xOPHj7tmTp9gyEQBQRQQRAFBFBCcPjEQ3759K+evXr1qdJ2JiYk2ltOInQKCKCCIAoIoIIgCgtOnIdra2irn7969K+cLCwvl/NSpU62taVA2NjbK+efPnxtd5/bt220spxE7BQRRQBAFBFFAEAUEp09DtLq6Ws7v379fznd2dsr52bNnW1vToDx//vy4l/Db7BQQRAFBFBBEAcEf2gOysrLSNXvw4MExrGSw9vf3y/n79+8bXefatWvlfHZ2tvGajspOAUEUEEQBQRQQRAHB6dMRbW5ulvNOp9M129vbK3/2T7hpqJcXL16U8+q1XL8yPz9fzk+fPt14TUdlp4AgCgiigCAKCKKA4PSpT9+/fy/na2tr5fzjx499X/vZs2fl/E+4majpA5MvXbpUzu/cudPGclphp4AgCgiigCAKCKKA4PSpT71Ok5aWlvq+xtWrV8v5zZs3f2dJI2F7e7vRz1+4cKGcT01NtbGcVtgpIIgCgiggiAKCKCA4fRqiXq+2Wl5eLuc3btxodP2ZmZlyfvHixUbXaWJ9fb3Rz1++fHlAK2mPnQKCKCCIAoIoIIgCwtjh4eEwP2+oH9amDx8+lPNeJz7HYXp6upwP8vTp9evX5bzXv6unT5+W81u3brW2pgbGqqGdAoIoIIgCgiggiAKC06c+ffnypZz3upvu06dPg1zOyJucnCznGxsb5fzcuXODXE4vTp+gH6KAIAoIooDgJqM+jY+Pl/O3b9+W8+rRNw8fPmx1TaNsbm6unB/TH9SN2CkgiAKCKCCIAoIoIPiax4D8+PGja3ZwcNDoGisrK+V8f3+/nPd6ePH58+fLefUVlV43JF25cqWcf/36tZx3Op1yfvfu3XJ+THzNA/ohCgiigCAKCKKA4LtPA3LyZPfvm2r2K/fu3WtrOX178uRJOe91yvR/ZKeAIAoIooAgCgiigCAKCKKAIAoIooAgCgiigCAKCKKAIAoIooAgCgiigODOO47kzJkz5XxxcXHIK2mPnQKCKCCIAoIoIIgCgtMnjqTXk9S3t7fLea+nmo8SOwUEUUAQBQRRQPB6L/5jd3e3nE9NTZVzr/eCv4AoIIgCgiggiAKC0yf+Zk6foB+igCAKCKKAIAoIooAgCgiigCAKCKKAIAoIw37ETfldExgldgoIooAgCgiigCAKCKKAIAoIooAgCgiigCAKCKKAIAoIooAgCgiigCAKCKKAIAoIooAgCgiigCAKCD8Bxu62ceBPCLoAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 216x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "x.show()\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x576 with 9 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def _plot(i,j,ax): data.train_ds[0][0].show(ax, cmap='gray')\n",
    "plot_multi(_plot, 3, 3, figsize=(8,8))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([128, 1, 28, 28]), torch.Size([128]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "xb,yb = data.one_batch()\n",
    "xb.shape,yb.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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gEAkUgAIRCIFgEAkUgAIRCIFgEAkUgAIRCIFgEAkUgAIRCIFgEAkUgAIRCIFgED53kYvL1avXu3izZs3S5JWrVrlyp588klJ0nfffefKrr32Whc3aNAg7j2/+OILFzdv3jx7lQUQY9myZZKkK664wpWNGzcu7nnt27d38b333uvinj175rB2idEiBYBA+T5FNOsf9vXXX0uShg0b5soWLVrk4vXr10uSFixYkPR9OnXq5OJHH31UkjRq1ChXNn78eBffc889kqRWrVq5sp9++kmS1KhRI1d2+OGHx33Ojz/+6OIrr7xSknTAAQe4siFDhrARcIb8XseECRNcbK+d/3O+9NJLXZzjHgbXMwU33niji0ePHi1J+uqrr1J+fbt27Vw8ZswYSVL37t2zVLsYbOwMALlAIgWAQEXftd97770lVd11T0fLli0lxXYt7C0CSTKm8t5anz59XOzfYhg0aJCkim6LJH366aeSpIsuusiV3X333XQF02Rv7/Tu3duVvffee0lfU7duXRe/+uqrkqRDDz00B7Wja78tO5gkSaeffrok6Z133nFldoA4U6eccookadKkSUHvUwm69gCQC0U//ckOFFTWIq1fv74kqV69enGPHXLIIS5u27ati2fOnClJGjp0qCvzW+6JWqR16tSRJNWsWfEj3WWXXVx83nnnSYodbNpxxx0l5eymeEmbPXu2i20vYMmSJSm/fs2aNS7+5S9/KUkaOHCgKxsxYkRgDeHze3fHHHOMi+fNmxf33GbNmkmK/f75UxLvv/9+SbE9Pp/toaxbt86V7bDDDplUO2W0SAEgEIkUAAIV/WCT7SpPnjw54eMdO3aUJO27777Z/ugq+asxbNfklltucWXPPPOMJKlJkyb+yxicSMLOCR08eLArswOB/i2X3XbbLe61dq6vJH3//fcutq+rVauWK7MDV08//XRolbmeqri1JVXM8/T587inTJkiKe574dj5wv7goB249Y0cOdLFV199dZo1rhSDTQCQCyRSAAhU9F376mzOnDkutl17O7ovJe5+iq5gHH95rp2Pu2nTJldm5yLa0XdJ+sUvfhH3Pv4IsX0fv9xfYlq7dm1J0kMPPeTKTjvtNBfb2SApKOvrecMNN0iK7Wb780TtLBd/1k2LFi1Seu/XXnvNxf4cYnsLx5+ps3LlypjPC0DXHgBygRZpltjWjH9T3Z/7dvbZZ0uKnUNXibJuwSRiBwylilZ+hw4dXNmMGTMkpdVKjPHKK69Iks444wxX5m/FaP3tb39z8YABA1J9+7K7nl9++aWL7VxtO7dTim1xPvLII5KkI488Mugzp06d6uJevXrFPb506VJJUtOmTYM+R7RIASA3SKQAEKjol4hWF8cff7wk6e2333Zl/fr1c3EKXXp47rzzThfPnTs37nF/ICHTLr117LHHSpL69u3ryvxuvOXvebvrrrtKkk444YSgzy5F/nfA79JbXbt2dXFol97yd8tPxO53+uCDD2bl87ZFixQAAtEiDeCvrnn33XclSTvttFPCx5Ge6dOnu9if6pRL3bp1c3GiFqm/leKzzz4riRapb+PGjZKkc845J+4xf+D18ssvz1udLLtaKldokQJAIBIpAASia5+BN954Q5L0+OOPuzK7EmbixImuLFs30hHPX2WULf4heHYFTGW3FWzX3x5gKKW+IqdU2Tnp/j6g1m9+8xsXH3jggXmrk5Vobmk20SIFgEAkUgAIRNc+RXYpmyT9+te/jnu8f//+kmK78/6xIsuXL497zWeffSZJat26tStr1apVcF1LmT2+5fzzz8/6ex933HEu7tKliyTpzTffTPhcO4J/xx13uDJ7BEa5mjBhQqWP+ctvc+Gpp55K+vhVV12V08+nRQoAgcqyRWpXWzRu3NiVbdiwIS72t2+76667XJzo8Dt7xKw9Claq2ChBSn48sL+ixh+sKmf+Zjp+fPHFF0sKX81UlR49ekiqGFisjL+VW7m76aabKn2ski0js2bx4sVxZf7hlj/72c9y+vm0SAEgEIkUAAKVZNfe7x7bQR6756Qk/ec//5Ek1a1b15X5u3bbuYP+Wdz+8sBEXfsXXngh7XraXb3Z0CSe/zOuLM4lO6e0qs/LV32qK7s0Woq9lZUP33zzjYv9kwwaNWokqWJ3fkmqUaNGTutCixQAApFIASBQSXbt/aMO7ChvNm2//faSYnd6OuywwyTFjhT6hg4dKin2doJdVprrbkcp+eijj/LyOWvWrMnL5xQ7O1tFSvwzs7etcjFq7x/34t96s7t4+fOCc40WKQAEKskWqX/Tu1atWpJi9wZt166dJGnWrFmu7Mknn4x7nwMOOMDF/l83uwHCUUcdlaUaY1u/+tWvXOzvuP7MM89Ikt566y1X5u+4ni2dO3eWJO29996uzD/O2fIHPBYuXCgpdqVauWvYsKGkiu9hpvxVgnYDFH8A2e/VFeJ7SYsUAAKRSAEgUEmea+9vEGK7+f4eiHY5mb9H4fz5811suwZPPPGEK7OHneVBMU1MzMv19G+r2O6c3bxEqjjXvk2bNln7zA8++EBSRRc/FbZuRx99tF9c0tdz5syZLrYDS/5+pPYc+dmzZ7syf2l2Mv7BeaNHj3bxyJEj45573nnnJXxuDnCuPQDkQkkONvlTLWxL8tNPP3VlJ510kqTYVmjHjh1d/OKLL0qqmOaEwjrzzDNdbFt9K1ascGW5aJGmugO/XUUj5X5jjurITvuTKo61njx5siuzqwMvvfRSV5boYEGf3SzIP30g0aopfyDQ3/inEGiRAkAgEikABCrJwSafneeXaD9Cu2mIFLvTud9lKICSHpzIxNq1a1184oknSordB9SuEPPnAttuphS7mszyN6SxXc05c+a4Mn+gMZF69epJit2sxu5huo2yuZ52dVGTJk1c2ffffx/3vKrmlNpNg/zc5M8TtfOG/V3xd9999wxqnBEGmwAgF0ikABCoLLv2zZo1kxTbLevQoUN+K1a5sukKZmL69OmSYo90Wb16ddzz/A1lEo3AjxkzxsWp7ilqbytI0ogRIyRJBx98cFUvK7vred9997n4+uuvlyStXLky7fexc1Al6YILLnDx8OHDA2oXjK49AORCybdI7c73X3zxhSuzB6flcbVSOsquBZMJf8MKO8901apVKb/e/71P1CK1xwcPGzbMlfmtT7sZRwrK+nra+Z8PPvigK/O327OnWdheolRxFLZ/7HmnTp2yXbVM0SIFgFwgkQJAoJLv2hehsu4KZsLOCR04cKArmzZtWtzzBg0a5GJ/aWefPn0kSa1atXJlLVq0kCRtt11wW4PrWVro2gNALtAirX5owZQWrmdpoUUKALlAIgWAQPnu2gNAyaFFCgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCBSKQAEIhECgCByi6RGmNqG2PGGmMWG2N+MMa8Z4w5odD1QhhjTD9jzCfGmDXGmIXGmB6FrhMyY4xpbIyZtPVaLjbGnF3oOlWlZqErUAA1JS2RdISkLySdKGmCMWb/KIo+L2TFkBljTE9Jt0n6paS3Jf2ssDVCoAckbZDURNIBkp43xnwQRdFHha1W5UwURYWuQ8EZY2ZLuj6KoomFrgvSZ4yZIWlsFEVjC10XhDHG1JO0UlKHKIrmby17TNKXURRdWdDKJVF2XfttGWOaSGonqdr+tUPljDE1JB0saVdjzKfGmKXGmFHGmDqFrhsy0k7SZptEt/pA0n4Fqk9KyjqRGmNqSXpc0qNRFM0tdH2QkSaSakn6haQe2tIV7Czp6kJWChmrL2n1NmWrJTUoQF1SVraJ1BiznaTHtOVezIUFrg4yt3br/94fRdGyKIpWSLpLW+59o/j8KKnhNmUNJf1QgLqkrCwTqTHGSBqrLa2Z06Mo2ljgKiFDURStlLRUEjf7S8N8STWNMW29sk6q5rfeyjKRSvqzpPaS+kRRtLaqJ6Pae0TSb40xuxljdpJ0saTJBa4TMhBF0RpJT0saaYypZ4z5uaRTtKX3WG2V3ai9MaaFpM8lrZe0yXtoWBRFjxekUgiy9V73vZLOlrRO0gRJV0RRtK6gFUNGjDGNJT0sqaekbyVdGUXR+MLWKrmyS6QAkG3l2rUHgKwhkQJAIBIpAAQikQJAoHxvWsLIVtVMoSuQBq5n1biepSXh9aRFCgCBSKQAEIhECgCBSKQAEKgcd8hHiXnllVckST179kz6vP/+978u7ty5c07rhPJCixQAApFIASAQXXsUlTVr1kiSzjnnHFc2a9YsSdKWbWYrV9XjQKZokQJAIFqkqPaWLl3q4jPPPFOS9NZbbxWqOkAcWqQAEIhECgCB6Npv9c0337j40UcflSRt3rzZlQ0fPjzp61u1aiVJmjp1qitr3bp1NqtYVr799lsX9+vXz8Wpdulr1qz41T7//PMlSW3btq3s6cijjRsrzpq86667JEm33nqrK3vuueckSd27d89vxQLQIgWAQCRSAAiU78PvqtV+h88884yLb775Zhe/8847Gb/nddddlzBOQzFNdsz69Vy2bJmkitF5SXrzzTfTfp8LLrjAxaNGjQqvWObK+npafnf+/vvvd/Hvf//7uOc2atRIktSxY0dXdvrpp7v47LPPliTVq1fPldWpUyd7lU2O/UgBIBfKukXqb1zxwQcfZOU9a9eu7eLx4yuO4u7bt2+qb1F2LRjbCpUqWqLptEL33ntvSdKkSZNcWfPmzV1ct27d0CqGKLvrmcjgwYNd/Mgjj6RWGS83JVqVtt9++7n4jjvucHGvXr0yqWKqaJECQC6QSAEgUFnOI12xYoUkae3atVl/7/Xr17t49erVWX//UjR27FgXZzKwZAcK99lnn6zVCdlhB24ffvhhV+Z30zt06CBJmjJliiuzt8feeOMNV/bhhx+62N4ymzdvnivzb50NGzZMknT33XeH/wekiBYpAAQqyxbpyy+/LEmaP39+gWtS3l588UVJ0p/+9Ke0X3vSSSe52A4uvPrqq67spptucvHHH3+c0nuee+65Lh45cqSk2BVSSJ/fkkzkd7/7nSSpadOmcY+dcsopCeOrr75aUuy0Nv9628Gs3r17u7Jjjz02nWqnjRYpAAQikQJAoLKcR7pgwQJJ0sknn+zKPv/8cxfvsMMOSV9vu31+l/Ghhx6Ke55/g33QoEGpVq+k5x363W+7y72/YUyq/MGJuXPnSpIuvvjitN+nMitXrpRUscomQElfz6rYjUf8QcRdd93VxcuXL8/K50yePNnFQ4YMkRQ78Ltw4UJJUuPGjUM/inmkAJALJFIACFSWQ5J2X8pPPvnElU2bNs3FxxxzjKTY7oK/KYJ9fOLEia4sUdce8fzbIal26f0R+jlz5kiKHcXdtGlTlmqHbPD3kv3yyy/jHh8xYkTWP9P/HbG31PwyexvP3y84mxud0CIFgEBl2SJNxLYyfRs2bHDxdtul9jfHX13Tv3//8IqVgB9//NHF/iqmVPnbrtnWjD3FIB3bb7+9i/1rm0hVj6Nyt99+u4sXL14sSWrfvr0rGzBgQE4/v2vXrpKkZs2aubIZM2ZIkn766SdXRosUAKoREikABKJrn8Rpp52W9PH3338/ruyaa65xcY0aNbJep2Lk3+DPZN9Xe7BgpuxO6yeeeKIr8w9bS8TeOki0gzsS++GHHyRJf/3rX+Me++1vf+vi+vXr57Qedq7o0KFDXZk9reLxxx93ZXZ5ajbQIgWAQLRIM7BkyRJJiQdOGjRokO/qVHuZDDClw27LdtZZZ7kyfwMSO7XtgQceSPk9/dYMUmOnAK5atcqV2dMLqurd5cL+++8fV+afokCLFACqERIpAASia5+BU089VZL09ddfuzI7oGHnsCF/7FG948aNc2VjxoxxcVUDS3vssYek2FsD/pxTVM6eNiFJl19+edzjf/jDHyRJTZo0yVudLLthilRxkJ4/QPzpp5+6uE2bNkGfRYsUAAKRSAEgEF37DPhdAqtly5aSpF122SXPtam+7OFlmcwdTce7774rSTrwwANdmd1/MhXdunWTFLu0EanxjxKxsyf878BRRx2V9zpZiepWq1YtV+bHoWiRAkAgWqRJ+KcHPP/88y62O2936tTJlY0ePTp/FSsS9ma//3NKtK1aqEWLFgW9/rbbbstSTcrP008/HVd20EEHubhFixb5rE6MRHXr16+fi7NZN1qkABB9WG/HAAADtUlEQVSIRAoAgejaJ+F35/2D8iy7074k7b777nmpUzG67777XOyfShDaJQ/hz3n0961E1WbNmuXiRCdD2LmjhfLUU09Jiq1bw4YNJUlXXXVVTj6TFikABCKRAkCgkunav/TSSy7OVpdxwoQJSR+359sjub322svFl1xyiYuzuftOMscee6ykiqW9ktSlSxcX16xZMl+DvNi4caOLEx08mGjXpVzzD6o888wzJVXMHZWkYcOGScrdUlVapAAQqCj/FN97770utgMZy5cvd2Vr1qzJ6efbjUkYYEqfv8+nXX00ZcoUVzZv3ry03/Pggw+WVNES2fZz7AYk2TzsDFv4c63zxR73PGrUKFfmH/FsB5YGDx7synI9V5gWKQAEIpECQCCT56Z50Icdf/zxkqTp06e7snXr1qX0Wn+uYOvWrSVJK1eudGWzZ89Ouz7+ufX27HXbrQhgqn5KtZGVX545c+a42G40MX78eFfmz+dNZOLEiZKkvn37ZqM62VZy19OfR9qjRw8X24Enf1Mff6AxXf5ep/YaS9Jjjz0mSXr77bddmT94aA+6s4OMWZbwetIiBYBA1b5F6v9VateunaTYw7Usf0fzRLtd+y0cu5u9v6P6gAED4l7jT5Xwf07+wJZlN+i48847XdkhhxwS97wUlFwLpsyV9PW0vURJevnllyXFHgB59NFHS6rYqlCq+B5XZsGCBZJiV5/5U5msCy+80MX+6rkco0UKALlAIgWAQNW+a+/vWn7llVfGPW53uR4+fLgrszebfWvXrnXx66+/Lin2sDN/4GnPPfeUFDu/ccOGDS7u06ePpNjD7+yNdv8G92WXXebiXr16xdWpEiXdFSxDJX09/e+N/T69+uqrrsx+L/w8k6ibnrAy3mv2228/F19zzTWSYjcSyuMcYbr2AJALJFIACFT0XXs7f2zmzJlJ38fvWk+dOjXucXu2uVQx+ti+ffuk73nRRRe52M4j9dWtW9fFdi7kEUcckfQ9VeJdwTJUdtfT/37deOONkmLnflfVtbe3zvx9TTt37uziAi/1pWsPALlQ7VukZajsWjAljutZWmiRAkAukEgBIBCJFAACkUgBIBCJFAACkUgBIBCJFAAC5XseKQCUHFqkABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABCIRAoAgUikABDo/wBgvTFnrFkURAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 360x360 with 9 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "data.show_batch(rows=3, figsize=(5,5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Basic CNN with batchnorm 批量正规化（归一化）的基础版CNN模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def conv(ni,nf): return nn.Conv2d(ni, nf, kernel_size=3, stride=2, padding=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = nn.Sequential(\n",
    "    conv(1, 8), # 14\n",
    "    nn.BatchNorm2d(8),\n",
    "    nn.ReLU(),\n",
    "    conv(8, 16), # 7\n",
    "    nn.BatchNorm2d(16),\n",
    "    nn.ReLU(),\n",
    "    conv(16, 32), # 4\n",
    "    nn.BatchNorm2d(32),\n",
    "    nn.ReLU(),\n",
    "    conv(32, 16), # 2\n",
    "    nn.BatchNorm2d(16),\n",
    "    nn.ReLU(),\n",
    "    conv(16, 10), # 1\n",
    "    nn.BatchNorm2d(10),\n",
    "    Flatten()     # remove (1,1) grid\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "learn = Learner(data, model, loss_func = nn.CrossEntropyLoss(), metrics=accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "======================================================================\n",
      "Layer (type)         Output Shape         Param #    Trainable \n",
      "======================================================================\n",
      "Conv2d               [128, 8, 14, 14]     80         True      \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 8, 14, 14]     16         True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 8, 14, 14]     0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 7, 7]      1168       True      \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 7, 7]      32         True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 7, 7]      0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 32, 4, 4]      4640       True      \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 32, 4, 4]      64         True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 32, 4, 4]      0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 2, 2]      4624       True      \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 2, 2]      32         True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 2, 2]      0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 10, 1, 1]      1450       True      \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 10, 1, 1]      20         True      \n",
      "______________________________________________________________________\n",
      "Flatten              [128, 10]            0          False     \n",
      "______________________________________________________________________\n",
      "\n",
      "Total params: 12126\n",
      "Total trainable params: 12126\n",
      "Total non-trainable params: 0\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(learn.summary())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xb = xb.cuda()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 10])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model(xb).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.\n"
     ]
    }
   ],
   "source": [
    "learn.lr_find(end_lr=100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "learn.recorder.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "Total time: 00:30 <p><table style='width:300px; margin-bottom:10px'>\n",
       "  <tr>\n",
       "    <th>epoch</th>\n",
       "    <th>train_loss</th>\n",
       "    <th>valid_loss</th>\n",
       "    <th>accuracy</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>1</th>\n",
       "    <th>0.223167</th>\n",
       "    <th>0.217859</th>\n",
       "    <th>0.930500</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>2</th>\n",
       "    <th>0.136179</th>\n",
       "    <th>0.078651</th>\n",
       "    <th>0.976400</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>3</th>\n",
       "    <th>0.072080</th>\n",
       "    <th>0.038664</th>\n",
       "    <th>0.988600</th>\n",
       "  </tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "learn.fit_one_cycle(3, max_lr=0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Refactor 重构"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def conv2(ni,nf): return conv_layer(ni,nf,stride=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = nn.Sequential(\n",
    "    conv2(1, 8),   # 14\n",
    "    conv2(8, 16),  # 7\n",
    "    conv2(16, 32), # 4\n",
    "    conv2(32, 16), # 2\n",
    "    conv2(16, 10), # 1\n",
    "    Flatten()      # remove (1,1) grid\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "learn = Learner(data, model, loss_func = nn.CrossEntropyLoss(), metrics=accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "Total time: 01:12 <p><table style='width:300px; margin-bottom:10px'>\n",
       "  <tr>\n",
       "    <th>epoch</th>\n",
       "    <th>train_loss</th>\n",
       "    <th>valid_loss</th>\n",
       "    <th>accuracy</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>1</th>\n",
       "    <th>0.228332</th>\n",
       "    <th>0.206325</th>\n",
       "    <th>0.937500</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>2</th>\n",
       "    <th>0.189966</th>\n",
       "    <th>0.192558</th>\n",
       "    <th>0.940800</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>3</th>\n",
       "    <th>0.156765</th>\n",
       "    <th>0.092810</th>\n",
       "    <th>0.969100</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>4</th>\n",
       "    <th>0.135871</th>\n",
       "    <th>0.083914</th>\n",
       "    <th>0.973300</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>5</th>\n",
       "    <th>0.108844</th>\n",
       "    <th>0.071582</th>\n",
       "    <th>0.978000</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>6</th>\n",
       "    <th>0.105887</th>\n",
       "    <th>0.128586</th>\n",
       "    <th>0.960200</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>7</th>\n",
       "    <th>0.080699</th>\n",
       "    <th>0.052754</th>\n",
       "    <th>0.983200</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>8</th>\n",
       "    <th>0.066007</th>\n",
       "    <th>0.037588</th>\n",
       "    <th>0.988600</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>9</th>\n",
       "    <th>0.047513</th>\n",
       "    <th>0.030255</th>\n",
       "    <th>0.990200</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>10</th>\n",
       "    <th>0.044705</th>\n",
       "    <th>0.028373</th>\n",
       "    <th>0.991600</th>\n",
       "  </tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "learn.fit_one_cycle(10, max_lr=0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Resnet-ish"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResBlock(nn.Module):\n",
    "    def __init__(self, nf):\n",
    "        super().__init__()\n",
    "        self.conv1 = conv_layer(nf,nf)\n",
    "        self.conv2 = conv_layer(nf,nf)\n",
    "        \n",
    "    def forward(self, x): return x + self.conv2(self.conv1(x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function res_block in module fastai.layers:\n",
      "\n",
      "res_block(nf, dense:bool=False, norm_type:Union[fastai.layers.NormType, NoneType]=<NormType.Batch: 1>, bottle:bool=False, **kwargs)\n",
      "    Resnet block of `nf` features.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(res_block)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = nn.Sequential(\n",
    "    conv2(1, 8),\n",
    "    res_block(8),\n",
    "    conv2(8, 16),\n",
    "    res_block(16),\n",
    "    conv2(16, 32),\n",
    "    res_block(32),\n",
    "    conv2(32, 16),\n",
    "    res_block(16),\n",
    "    conv2(16, 10),\n",
    "    Flatten()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def conv_and_res(ni,nf): return nn.Sequential(conv2(ni, nf), res_block(nf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = nn.Sequential(\n",
    "    conv_and_res(1, 8),\n",
    "    conv_and_res(8, 16),\n",
    "    conv_and_res(16, 32),\n",
    "    conv_and_res(32, 16),\n",
    "    conv2(16, 10),\n",
    "    Flatten()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "learn = Learner(data, model, loss_func = nn.CrossEntropyLoss(), metrics=accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "learn.lr_find(end_lr=100)\n",
    "learn.recorder.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "Total time: 02:00 <p><table style='width:300px; margin-bottom:10px'>\n",
       "  <tr>\n",
       "    <th>epoch</th>\n",
       "    <th>train_loss</th>\n",
       "    <th>valid_loss</th>\n",
       "    <th>accuracy</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>1</th>\n",
       "    <th>0.248807</th>\n",
       "    <th>0.121582</th>\n",
       "    <th>0.972800</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>2</th>\n",
       "    <th>0.120927</th>\n",
       "    <th>0.360583</th>\n",
       "    <th>0.890300</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>3</th>\n",
       "    <th>0.104013</th>\n",
       "    <th>0.074916</th>\n",
       "    <th>0.977800</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>4</th>\n",
       "    <th>0.081181</th>\n",
       "    <th>0.065717</th>\n",
       "    <th>0.980000</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>5</th>\n",
       "    <th>0.068514</th>\n",
       "    <th>0.096448</th>\n",
       "    <th>0.967200</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>6</th>\n",
       "    <th>0.061274</th>\n",
       "    <th>0.087955</th>\n",
       "    <th>0.971800</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>7</th>\n",
       "    <th>0.051673</th>\n",
       "    <th>0.033911</th>\n",
       "    <th>0.989400</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>8</th>\n",
       "    <th>0.048090</th>\n",
       "    <th>0.033234</th>\n",
       "    <th>0.988800</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>9</th>\n",
       "    <th>0.039095</th>\n",
       "    <th>0.024638</th>\n",
       "    <th>0.992400</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>10</th>\n",
       "    <th>0.023670</th>\n",
       "    <th>0.021215</th>\n",
       "    <th>0.993400</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>11</th>\n",
       "    <th>0.019128</th>\n",
       "    <th>0.016159</th>\n",
       "    <th>0.994500</th>\n",
       "  </tr>\n",
       "  <tr>\n",
       "    <th>12</th>\n",
       "    <th>0.021365</th>\n",
       "    <th>0.016120</th>\n",
       "    <th>0.995200</th>\n",
       "  </tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "learn.fit_one_cycle(12, max_lr=0.05)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "======================================================================\n",
      "Layer (type)         Output Shape         Param #    Trainable \n",
      "======================================================================\n",
      "Conv2d               [128, 8, 14, 14]     72         True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 8, 14, 14]     0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 8, 14, 14]     16         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 8, 14, 14]     576        True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 8, 14, 14]     0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 8, 14, 14]     16         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 8, 14, 14]     576        True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 8, 14, 14]     0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 8, 14, 14]     16         True      \n",
      "______________________________________________________________________\n",
      "MergeLayer           [128, 8, 14, 14]     0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 7, 7]      1152       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 7, 7]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 7, 7]      32         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 7, 7]      2304       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 7, 7]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 7, 7]      32         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 7, 7]      2304       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 7, 7]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 7, 7]      32         True      \n",
      "______________________________________________________________________\n",
      "MergeLayer           [128, 16, 7, 7]      0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 32, 4, 4]      4608       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 32, 4, 4]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 32, 4, 4]      64         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 32, 4, 4]      9216       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 32, 4, 4]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 32, 4, 4]      64         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 32, 4, 4]      9216       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 32, 4, 4]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 32, 4, 4]      64         True      \n",
      "______________________________________________________________________\n",
      "MergeLayer           [128, 32, 4, 4]      0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 2, 2]      4608       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 2, 2]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 2, 2]      32         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 2, 2]      2304       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 2, 2]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 2, 2]      32         True      \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 16, 2, 2]      2304       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 16, 2, 2]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 16, 2, 2]      32         True      \n",
      "______________________________________________________________________\n",
      "MergeLayer           [128, 16, 2, 2]      0          False     \n",
      "______________________________________________________________________\n",
      "Conv2d               [128, 10, 1, 1]      1440       True      \n",
      "______________________________________________________________________\n",
      "ReLU                 [128, 10, 1, 1]      0          False     \n",
      "______________________________________________________________________\n",
      "BatchNorm2d          [128, 10, 1, 1]      20         True      \n",
      "______________________________________________________________________\n",
      "Flatten              [128, 10]            0          False     \n",
      "______________________________________________________________________\n",
      "\n",
      "Total params: 41132\n",
      "Total trainable params: 41132\n",
      "Total non-trainable params: 0\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(learn.summary())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
